import re
import json
import uuid
from datetime import datetime
import logging
from typing import List, Dict, Any, Optional, Callable

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('RuleDSL')

class Rule:
    """交易规则类，存储规则的各种属性和方法"""
    def __init__(self, rule_id=None, symbol=None, condition=None, action=None, params=None):
        self.id = rule_id or str(uuid.uuid4())
        self.symbol = symbol
        self.condition = condition
        self.action = action
        self.params = params or {}
        self.created_at = datetime.now().timestamp()
        self.updated_at = datetime.now().timestamp()
        self.trigger_count = 0
        self.last_triggered_at = None
    
    def calc_position_size(self):
        """计算仓位大小"""
        # 实际应用中，这里应该使用更复杂的资金管理算法
        default_size = self.params.get('default_size', 100)
        risk_percent = self.params.get('risk_percent', 0.02)
        account_balance = self.params.get('account_balance', 100000)
        stop_loss = self.params.get('stop_loss', 0.01)  # 1%止损
        
        # 基于风险的仓位计算：风险金额 = 账户余额 * 风险百分比
        risk_amount = account_balance * risk_percent
        
        # 手数 = 风险金额 / (止损金额 * 合约价值)
        # 这里简化计算
        position_size = int(risk_amount / (stop_loss * account_balance * 0.01))
        
        # 确保仓位大小在合理范围内
        min_size = self.params.get('min_size', 10)
        max_size = self.params.get('max_size', 1000)
        
        return max(min_size, min(max_size, position_size))
    
    @property
    def execution_strategy(self):
        """获取执行策略"""
        return self.params.get('execution_strategy', 'MARKET')  # 默认市价单
    
    def to_dict(self):
        """将规则转换为字典格式"""
        return {
            'id': self.id,
            'symbol': self.symbol,
            'condition': self.condition,
            'action': self.action,
            'params': self.params,
            'created_at': self.created_at,
            'updated_at': self.updated_at,
            'trigger_count': self.trigger_count,
            'last_triggered_at': self.last_triggered_at
        }
    
    def update(self, **kwargs):
        """更新规则属性"""
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)
        self.updated_at = datetime.now().timestamp()
    
    def __str__(self):
        return f"Rule(id={self.id}, symbol={self.symbol}, condition={self.condition}, action={self.action})"

class RuleDSL:
    """策略规则解释器，支持自然语言策略编辑和规则触发检测"""
    def __init__(self, config=None):
        self.config = config or {
            'max_rules': 1000,  # 最大规则数量
            'cache_size': 1000,  # 缓存大小
            'enable_nlp': True,  # 启用自然语言处理
            'rule_history_size': 1000  # 规则历史记录大小
        }
        
        # 存储规则
        self.rules: Dict[str, Rule] = {}
        
        # 规则历史记录
        self.rule_history = []
        
        # 自然语言到条件的映射
        self.nlp_patterns = [
            # 突破均线模式
            (r'突破(\d+)日均线且成交量放大(\d+(\.\d+)?)倍时追涨', self._parse_ma_volume_rule),
            (r'跌破(\d+)日均线且成交量放大(\d+(\.\d+)?)倍时杀跌', self._parse_ma_volume_rule),
            
            # RSI超买超卖模式
            (r'RSI\((\d+)\)上穿(\d+)买入', self._parse_rsi_crossover_rule),
            (r'RSI\((\d+)\)下穿(\d+)卖出', self._parse_rsi_crossover_rule),
            
            # MACD交叉模式
            (r'MACD金叉买入', self._parse_macd_crossover_rule),
            (r'MACD死叉卖出', self._parse_macd_crossover_rule),
            
            # 价格区间突破
            (r'价格突破(\d+\.?\d*)买入', self._parse_price_breakout_rule),
            (r'价格跌破(\d+\.?\d*)卖出', self._parse_price_breakout_rule),
            
            # 布林带策略
            (r'价格触及布林带上轨卖出', self._parse_bollinger_band_rule),
            (r'价格触及布林带下轨买入', self._parse_bollinger_band_rule)
        ]
    
    def add_rule(self, rule_data: Dict[str, Any]) -> Dict[str, Any]:
        """添加新规则"""
        if len(self.rules) >= self.config['max_rules']:
            return {'success': False, 'error': 'Maximum number of rules reached'}
        
        try:
            # 检查是否为自然语言规则
            if 'natural_language' in rule_data and self.config['enable_nlp']:
                # 解析自然语言规则
                parsed_rule = self._parse_natural_language(rule_data['natural_language'])
                if not parsed_rule['success']:
                    return parsed_rule
                
                # 合并解析结果和其他参数
                rule_data.update(parsed_rule.get('rule_data', {}))
            
            # 创建规则对象
            rule = Rule(
                symbol=rule_data.get('symbol'),
                condition=rule_data.get('condition'),
                action=rule_data.get('action'),
                params=rule_data.get('params', {})
            )
            
            # 保存规则
            self.rules[rule.id] = rule
            
            # 记录历史
            self._record_history('ADD', rule.id)
            
            logger.info(f"Added rule: {rule.id}")
            return {'success': True, 'rule_id': rule.id}
        except Exception as e:
            logger.error(f"Error adding rule: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def remove_rule(self, rule_id: str) -> Dict[str, Any]:
        """移除规则"""
        if rule_id not in self.rules:
            return {'success': False, 'error': 'Rule not found'}
        
        try:
            del self.rules[rule_id]
            self._record_history('REMOVE', rule_id)
            logger.info(f"Removed rule: {rule_id}")
            return {'success': True}
        except Exception as e:
            logger.error(f"Error removing rule: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def update_rule(self, rule_id: str, updates: Dict[str, Any]) -> Dict[str, Any]:
        """更新规则"""
        if rule_id not in self.rules:
            return {'success': False, 'error': 'Rule not found'}
        
        try:
            rule = self.rules[rule_id]
            rule.update(**updates)
            self._record_history('UPDATE', rule_id)
            logger.info(f"Updated rule: {rule_id}")
            return {'success': True}
        except Exception as e:
            logger.error(f"Error updating rule: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def get_rule(self, rule_id: str) -> Optional[Rule]:
        """获取规则"""
        return self.rules.get(rule_id)
    
    def get_all_rules(self) -> List[Dict[str, Any]]:
        """获取所有规则"""
        return [rule.to_dict() for rule in self.rules.values()]
    
    def check_rules(self, market_data: Dict[str, Any]) -> List[Rule]:
        """检查哪些规则被触发"""
        triggered_rules = []
        
        for rule_id, rule in self.rules.items():
            try:
                if self._evaluate_condition(rule.condition, market_data, rule):
                    # 更新触发计数和时间
                    rule.trigger_count += 1
                    rule.last_triggered_at = datetime.now().timestamp()
                    
                    # 记录触发历史
                    self._record_history('TRIGGER', rule_id)
                    
                    triggered_rules.append(rule)
            except Exception as e:
                logger.error(f"Error evaluating rule {rule_id}: {str(e)}")
        
        return triggered_rules
    
    def _evaluate_condition(self, condition: str, market_data: Dict[str, Any], rule: Rule) -> bool:
        """评估条件是否满足"""
        # 实际应用中，这里应该使用更复杂的表达式解析器
        # 这里使用简单的示例逻辑
        if not condition:
            return False
            
        # 获取股票数据
        symbol_data = market_data.get('market_data', {}).get(rule.symbol, {})
        
        # 示例：检查是否突破均线
        if 'ma_breakout' in condition:
            ma_period = int(condition.split('_')[-1])
            prices = symbol_data.get('prices', [])
            
            if len(prices) >= ma_period:
                ma_value = sum(prices[-ma_period:]) / ma_period
                current_price = prices[-1] if prices else 0
                
                if 'up' in condition:
                    return current_price > ma_value * 1.01  # 突破均线1%
                else:
                    return current_price < ma_value * 0.99  # 跌破均线1%
        
        # 示例：检查成交量放大
        if 'volume_spike' in condition:
            volumes = symbol_data.get('volumes', [])
            
            if len(volumes) >= 20:
                avg_volume = sum(volumes[-20:-1]) / 19  # 过去19天平均成交量
                current_volume = volumes[-1] if volumes else 0
                
                if '2x' in condition:
                    return current_volume >= avg_volume * 2
                elif '3x' in condition:
                    return current_volume >= avg_volume * 3
        
        # 示例：检查价格区间突破
        if 'price_breakout' in condition:
            breakout_price = float(condition.split('_')[-1])
            current_price = symbol_data.get('last_price', 0)
            
            if 'above' in condition:
                return current_price > breakout_price
            else:
                return current_price < breakout_price
        
        # 默认返回False
        return False
    
    def _parse_natural_language(self, natural_language: str) -> Dict[str, Any]:
        """解析自然语言规则"""
        try:
            # 尝试匹配预定义的模式
            for pattern, parser_func in self.nlp_patterns:
                match = re.search(pattern, natural_language)
                if match:
                    return parser_func(match, natural_language)
            
            # 如果没有匹配到预定义模式，返回错误
            return {'success': False, 'error': 'Unable to parse natural language rule'}
        except Exception as e:
            logger.error(f"Error parsing natural language: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def _parse_ma_volume_rule(self, match: re.Match, natural_language: str) -> Dict[str, Any]:
        """解析均线和成交量规则"""
        ma_period = int(match.group(1))
        volume_multiplier = float(match.group(2))
        
        action = 'BUY' if '追涨' in natural_language else 'SELL'
        condition_type = 'up' if action == 'BUY' else 'down'
        
        rule_data = {
            'condition': f'ma_breakout_{ma_period}_{condition_type}_volume_{volume_multiplier}x',
            'action': action,
            'params': {
                'ma_period': ma_period,
                'volume_multiplier': volume_multiplier,
                'natural_language': natural_language
            }
        }
        
        return {'success': True, 'rule_data': rule_data}
    
    def _parse_rsi_crossover_rule(self, match: re.Match, natural_language: str) -> Dict[str, Any]:
        """解析RSI交叉规则"""
        rsi_period = int(match.group(1))
        threshold = int(match.group(2))
        
        action = 'BUY' if '买入' in natural_language else 'SELL'
        cross_type = 'up' if action == 'BUY' else 'down'
        
        rule_data = {
            'condition': f'rsi_crossover_{rsi_period}_{threshold}_{cross_type}',
            'action': action,
            'params': {
                'rsi_period': rsi_period,
                'threshold': threshold,
                'natural_language': natural_language
            }
        }
        
        return {'success': True, 'rule_data': rule_data}
    
    def _parse_macd_crossover_rule(self, match: re.Match, natural_language: str) -> Dict[str, Any]:
        """解析MACD交叉规则"""
        action = 'BUY' if '金叉' in natural_language else 'SELL'
        cross_type = 'golden' if action == 'BUY' else 'death'
        
        rule_data = {
            'condition': f'macd_crossover_{cross_type}',
            'action': action,
            'params': {
                'natural_language': natural_language
            }
        }
        
        return {'success': True, 'rule_data': rule_data}
    
    def _parse_price_breakout_rule(self, match: re.Match, natural_language: str) -> Dict[str, Any]:
        """解析价格突破规则"""
        breakout_price = float(match.group(1))
        action = 'BUY' if '买入' in natural_language else 'SELL'
        breakout_type = 'above' if action == 'BUY' else 'below'
        
        rule_data = {
            'condition': f'price_breakout_{breakout_price}_{breakout_type}',
            'action': action,
            'params': {
                'breakout_price': breakout_price,
                'natural_language': natural_language
            }
        }
        
        return {'success': True, 'rule_data': rule_data}
    
    def _parse_bollinger_band_rule(self, match: re.Match, natural_language: str) -> Dict[str, Any]:
        """解析布林带规则"""
        action = 'SELL' if '上轨' in natural_language else 'BUY'
        band_type = 'upper' if action == 'SELL' else 'lower'
        
        rule_data = {
            'condition': f'bollinger_band_{band_type}_touch',
            'action': action,
            'params': {
                'natural_language': natural_language
            }
        }
        
        return {'success': True, 'rule_data': rule_data}
    
    def _record_history(self, event_type: str, rule_id: str):
        """记录规则历史"""
        history_record = {
            'timestamp': datetime.now().timestamp(),
            'event_type': event_type,
            'rule_id': rule_id
        }
        
        self.rule_history.append(history_record)
        
        # 限制历史记录大小
        if len(self.rule_history) > self.config['rule_history_size']:
            self.rule_history.pop(0)
    
    def get_rule_history(self, rule_id: str = None, event_type: str = None) -> List[Dict[str, Any]]:
        """获取规则历史记录"""
        filtered_history = self.rule_history
        
        if rule_id:
            filtered_history = [h for h in filtered_history if h['rule_id'] == rule_id]
        
        if event_type:
            filtered_history = [h for h in filtered_history if h['event_type'] == event_type]
        
        return filtered_history
    
    def clear_all_rules(self) -> Dict[str, Any]:
        """清除所有规则"""
        try:
            self.rules.clear()
            self._record_history('CLEAR_ALL', 'ALL')
            logger.info("Cleared all rules")
            return {'success': True}
        except Exception as e:
            logger.error(f"Error clearing all rules: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def export_rules(self) -> str:
        """导出所有规则为JSON格式"""
        rules_list = self.get_all_rules()
        return json.dumps(rules_list, indent=2)
    
    def import_rules(self, rules_json: str) -> Dict[str, Any]:
        """从JSON格式导入规则"""
        try:
            rules_list = json.loads(rules_json)
            
            for rule_data in rules_list:
                # 移除id字段，让系统自动生成新的id
                rule_data.pop('id', None)
                result = self.add_rule(rule_data)
                
                if not result['success']:
                    logger.error(f"Failed to import rule: {result.get('error')}")
                    
            logger.info(f"Imported {len(rules_list)} rules")
            return {'success': True, 'imported_count': len(rules_list)}
        except Exception as e:
            logger.error(f"Error importing rules: {str(e)}")
            return {'success': False, 'error': str(e)}

# 示例使用
if __name__ == "__main__":
    # 创建RuleDSL实例
    rule_dsl = RuleDSL()
    
    # 添加自然语言规则
    result = rule_dsl.add_rule({
        'symbol': 'AAPL',
        'natural_language': '突破20日均线且成交量放大2倍时追涨'
    })
    
    print(f"Add rule result: {result}")
    
    # 获取所有规则
    all_rules = rule_dsl.get_all_rules()
    print(f"All rules: {all_rules}")
    
    # 模拟市场数据检查规则
    mock_market_data = {
        'market_data': {
            'AAPL': {
                'prices': list(range(100, 120)),  # 价格逐渐上涨
                'volumes': [100] * 19 + [300]  # 最后一天成交量放大3倍
            }
        }
    }
    
    triggered = rule_dsl.check_rules(mock_market_data)
    print(f"Triggered rules: {[str(rule) for rule in triggered]}")